package net.lab1024.sa.user.module.system.user.service;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import cn.hutool.extra.servlet.ServletUtil;
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import net.lab1024.sa.common.common.code.UserErrorCode;
import net.lab1024.sa.common.common.constant.RequestHeaderConst;
import net.lab1024.sa.common.common.domain.ResponseDTO;
import net.lab1024.sa.common.common.enumeration.UserTypeEnum;
import net.lab1024.sa.common.module.support.loginlog.LoginLogResultEnum;
import net.lab1024.sa.common.module.support.loginlog.LoginLogService;
import net.lab1024.sa.common.module.support.loginlog.domain.LoginLogEntity;
import net.lab1024.sa.common.module.support.loginlog.domain.LoginLogVO;
import net.lab1024.sa.common.module.support.token.LoginDeviceEnum;
import net.lab1024.sa.common.module.support.token.TokenService;
import net.lab1024.sa.user.module.system.user.domain.entity.UserEntity;
import net.lab1024.sa.user.module.system.user.domain.form.UserAddForm;
import net.lab1024.sa.user.module.system.user.domain.form.WechatLoginForm;

import net.lab1024.sa.user.module.system.user.domain.form.WechatRegisterForm;
import net.lab1024.sa.user.module.system.user.domain.vo.LoginUserDetail;
import net.lab1024.sa.user.module.system.user.domain.vo.UserVO;
import net.lab1024.sa.user.module.system.user.domain.vo.WechatLoginVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentMap;

@Slf4j
@Service
public class LoginService {

    @Autowired
    private WxMaService wxMaService;


    @Autowired
    private UserService userService;


    @Autowired
    private TokenService tokenService;


    @Autowired
    private LoginLogService loginLogService;

    /**
     * 登录信息二级缓存
     */
    private ConcurrentMap<Long, LoginUserDetail> loginUserDetailCache = new ConcurrentLinkedHashMap.Builder<Long, LoginUserDetail>().maximumWeightedCapacity(1000).build();




    public ResponseDTO<LoginUserDetail> login(WechatLoginForm wechatLogin,String ip, String userAgent){


        LoginUserDetail loginUserDetail=new LoginUserDetail();
        WxMaJscode2SessionResult wxMaJscode2SessionResult =null;
        try {
            wxMaJscode2SessionResult=wxMaService.getUserService().getSessionInfo(wechatLogin.getCode());

        } catch (WxErrorException e) {
            log.error("微信登录获取OPENID失败:",e);
        }

        ResponseDTO<UserVO> userVOResponseDTO = userService.queryDetailByOpenId(wxMaJscode2SessionResult.getOpenid());

        if(!userVOResponseDTO.getOk()){

            return ResponseDTO.userErrorParam("没有进行微信注册");
        }

        BeanUtils.copyProperties(userVOResponseDTO.getData(),loginUserDetail);




        loginUserDetail.setUserType(UserTypeEnum.USER);
        loginUserDetail.setIp(ip);
        loginUserDetail.setUserAgent(userAgent);

        //生成token
        String token = tokenService.generateToken(loginUserDetail.getUserId().longValue(), loginUserDetail.getNickname(), UserTypeEnum.USER, LoginDeviceEnum.WEIXIN_MP, false);

        loginUserDetail.setToken(token);

        //加载上次登录信息
        LoginLogVO loginLogVO = loginLogService.queryLastByUserId(loginUserDetail.getUserId().longValue(), UserTypeEnum.USER);
        if (loginLogVO != null) {
            loginUserDetail.setLastLoginIp(loginLogVO.getLoginIp());
            loginUserDetail.setLastLoginTime(loginLogVO.getCreateTime());
            loginUserDetail.setLastLoginUserAgent(loginLogVO.getUserAgent());
        }

        //记录登录日志
        LoginLogEntity loginEntity = LoginLogEntity.builder()
                .userId(loginUserDetail.getUserId().longValue())
                .userType(UserTypeEnum.USER.getValue())
                .userName(loginUserDetail.getUserName())
                .userAgent(userAgent)
                .loginIp(ip)
                .remark(LoginDeviceEnum.WEIXIN_MP.getDesc())
                .loginResult(LoginLogResultEnum.LOGIN_SUCCESS.getValue())
                .createTime(LocalDateTime.now())
                .build();
        loginLogService.log(loginEntity);
        return ResponseDTO.ok(loginUserDetail);
    }


    @Transactional
    public ResponseDTO<LoginUserDetail> register(WechatRegisterForm wechatRegisterForm, String ip, String userAgent){

        LoginUserDetail loginUserDetail=new LoginUserDetail();


        WxMaJscode2SessionResult wxMaJscode2SessionResult = null;
        try {
            wxMaJscode2SessionResult = wxMaService.getUserService().getSessionInfo(wechatRegisterForm.getCode());
        } catch (WxErrorException e) {
            log.error("微信注册获取OPENID失败:",e);
        }


        UserAddForm userAddForm=new UserAddForm();

        userAddForm.setOpenId(wxMaJscode2SessionResult.getOpenid());

        userAddForm.setAvatarUrl(wechatRegisterForm.getAvatarUrl());

        userAddForm.setNickname(wechatRegisterForm.getNickname());

        userAddForm.setSessionKey(wxMaJscode2SessionResult.getSessionKey());

        userAddForm.setUnionId(wxMaJscode2SessionResult.getUnionid());

        ResponseDTO<UserVO> userVOResponseDTO = userService.queryDetailByOpenId(wxMaJscode2SessionResult.getOpenid());

        if(userVOResponseDTO.getCode().equals(ResponseDTO.OK_CODE)){
            return ResponseDTO.error(UserErrorCode.ALREADY_EXIST);
        }


        ResponseDTO<String> addResponseDTO = userService.add(userAddForm);

        if(addResponseDTO.getCode().equals(ResponseDTO.OK_CODE)){
            Long userId = Long.parseLong(addResponseDTO.getData());

            //记录登录日志
            LoginLogEntity loginEntity = LoginLogEntity.builder()
                    .userId(userId.longValue())
                    .userType(UserTypeEnum.USER.getValue())
                    .userName(wechatRegisterForm.getNickname())
                    .userAgent(userAgent)
                    .loginIp(ip)
                    .remark(LoginDeviceEnum.WEIXIN_MP.getDesc())
                    .loginResult(LoginLogResultEnum.LOGIN_SUCCESS.getValue())
                    .createTime(LocalDateTime.now())
                    .build();
            loginLogService.log(loginEntity);


            loginUserDetail.setNickname(wechatRegisterForm.getNickname());
            loginUserDetail.setAvatarUrl(wechatRegisterForm.getAvatarUrl());
            loginUserDetail.setUserId(userId);
            loginUserDetail.setUserType(UserTypeEnum.USER);
            loginUserDetail.setIp(ip);
            loginUserDetail.setUserAgent(userAgent);

            //生成token
            String token = tokenService.generateToken(userId.longValue(), wechatRegisterForm.getNickname(), UserTypeEnum.USER, LoginDeviceEnum.WEIXIN_MP, false);

            loginUserDetail.setToken(token);

            //加载上次登录信息
            LoginLogVO loginLogVO = loginLogService.queryLastByUserId(userId.longValue(), UserTypeEnum.USER);
            if (loginLogVO != null) {
                loginUserDetail.setLastLoginIp(loginLogVO.getLoginIp());
                loginUserDetail.setLastLoginTime(loginLogVO.getCreateTime());
                loginUserDetail.setLastLoginUserAgent(loginLogVO.getUserAgent());
            }



        }


        return ResponseDTO.ok(loginUserDetail);

    }

    public LoginUserDetail getLoginUserDetail(String token, HttpServletRequest request) {
        Long requestUserId = tokenService.getUserIdAndValidateToken(token);
        if (requestUserId == null) {
            return null;
        }
        // 查询用户信息
        LoginUserDetail loginUserDetail = loginUserDetailCache.get(requestUserId);
        if (loginUserDetail == null) {
            // 员工基本信息
            UserEntity userEntity = userService.getById(requestUserId);
            if (userEntity == null) {
                return null;
            }
            loginUserDetail=new LoginUserDetail();

            BeanUtils.copyProperties(userEntity,loginUserDetail);
            loginUserDetail.setToken(token);
            loginUserDetail.setUserType(UserTypeEnum.USER);


            //加载上次登录信息
            LoginLogVO loginLogVO = loginLogService.queryLastByUserId(userEntity.getUserId(), UserTypeEnum.USER);
            if (loginLogVO != null) {
                loginUserDetail.setLastLoginIp(loginLogVO.getLoginIp());
                loginUserDetail.setLastLoginTime(loginLogVO.getCreateTime());
                loginUserDetail.setLastLoginUserAgent(loginLogVO.getUserAgent());
            }

            loginUserDetailCache.put(requestUserId, loginUserDetail);
        }

        //更新请求ip和user agent
        loginUserDetail.setUserAgent(ServletUtil.getHeaderIgnoreCase(request, RequestHeaderConst.USER_AGENT));
        loginUserDetail.setIp(ServletUtil.getClientIP(request));

        return loginUserDetail;
    }
}
